package com.dd.cloud.common.config.advice;

import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeAuthException;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.vo.EnumResultVo;
import com.dd.cloud.common.vo.ExceptionResult;
import com.dd.cloud.common.vo.ZekeResponse;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.springframework.core.annotation.Order;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.time.format.DateTimeParseException;
import java.util.List;

/**
 * AOP捕获控制器异常，并统一处理
 * 通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。
 * 注解了@Controller的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。
 * 注解了@ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上
 *
 * @author vodbook
 */
@Slf4j
@RestControllerAdvice
public class CommonExceptionHandler {

    /**
     * 处理对内接口系统业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ZekeException.class)
    public ResponseEntity<ExceptionResult> handleZkopException(ZekeException e) {
        if (e.getEnumInterface() != null && e.getEnumInterface().getMessage() != null) {
            EnumResultVo vo = e.getEnumInterface().getMessage();
            return ResponseEntity.status(vo.getCode())
                    .body(new ExceptionResult(vo));
        }
        return ResponseEntity.status(e.getStatus())
                .body(new ExceptionResult(e.getStatus(), e.getData(), e.getMsg()));
    }

    /**
     * 处理对外接口系统业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ZekeAuthException.class)
    public ZekeResponse zekeAuthException(ZekeAuthException e) {
        if (e.getEnumInterface() != null && e.getEnumInterface().getMessage() != null) {
            return new ZekeResponse(e.getEnumInterface());
        }
        return new ZekeResponse(e);
    }

    /**
     * 处理 @Valid或＠Validated 和 @RequestBody 注解一起用的数据效验返回的错误信息格式
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ExceptionResult> handleBindException(MethodArgumentNotValidException e) {
        return getExceptionResultResponseEntity(e.getBindingResult());
    }

    /**
     * 处理validation数据校验返回的错误信息格式
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    public ResponseEntity<ExceptionResult> handleBindException(BindException e) {
        return getExceptionResultResponseEntity(e.getBindingResult());
    }

    public ResponseEntity<ExceptionResult> getExceptionResultResponseEntity(BindingResult bindingResult) {
        StringBuilder sb = new StringBuilder();
        List<FieldError> list = bindingResult.getFieldErrors();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i).getDefaultMessage());
            if (i != list.size() - 1) {
                sb.append(",");
            }
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST.value())
                .body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, sb.toString()));
    }

    /**
     * 处理validation单个数据效验的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ExceptionResult> handleViolaException(ConstraintViolationException e) {
        String fieldErrors = "";
        for (ConstraintViolation<?> item : e.getConstraintViolations()) {
            fieldErrors += item.getMessage() + ",";
        }
        fieldErrors.substring(0, fieldErrors.length() - 1);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, fieldErrors));
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<ExceptionResult> handleException(HttpRequestMethodNotSupportedException e) {
        e.printStackTrace();
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, "只接受" + StringUtils.arrayToDelimitedString(e.getSupportedMethods(), ",") + "请求"));
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<ExceptionResult> handleException(HttpMessageNotReadableException e) {
        e.printStackTrace();
        String errors = "";
        if (e.getCause() instanceof InvalidFormatException) {
            InvalidFormatException invalidFormatException = (InvalidFormatException) e.getCause();
            List<JsonMappingException.Reference> path = invalidFormatException.getPath();
            for(JsonMappingException.Reference reference : path){
                errors += "参数名："+reference.getFieldName()+" 输入不合法，需要的是 "+invalidFormatException.getTargetType().getName() + " 类型，"+"提交的值是："+invalidFormatException.getValue().toString();
            }
        }
        if (!"".equals(errors)){
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                    body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, errors));
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, "参数不能空"));
    }

//
//    /**
//     *
//     * @param e
//     * @return
//     */
//    @ExceptionHandler(MysqlDataTruncation.class)
//    public ResponseEntity<ExceptionResult> dateRangeException(InvalidFormatException e) {
//        e.printStackTrace();
//
//        String errors = "";
//        List<JsonMappingException.Reference> path = e.getPath();
//        for(JsonMappingException.Reference reference : path){
//            errors += "参数名："+reference.getFieldName()+" 输入不合法，需要的是 "+e.getTargetType().getName() + " 类型，"+"提交的值是："+e.getValue().toString();
//        }
//        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
//                body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, "参数解析失败: "+ errors));
//    }


    @ExceptionHandler(InvalidFormatException.class)
    public ResponseEntity<ExceptionResult> formatException(InvalidFormatException e) {
        e.printStackTrace();

        String errors = "";
        List<JsonMappingException.Reference> path = e.getPath();
        for(JsonMappingException.Reference reference : path){
            errors += "参数名："+reference.getFieldName()+" 输入不合法，需要的是 "+e.getTargetType().getName() + " 类型，"+"提交的值是："+e.getValue().toString();
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(HttpStatus.BAD_REQUEST.value(), null, "参数解析失败: "+ errors));
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ExceptionResult> handleException(MethodArgumentTypeMismatchException e) {
        e.printStackTrace();
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(400, null, e.getName() + "参数类型不匹配"));
    }

    @ExceptionHandler(value = NumberFormatException.class)
    public ResponseEntity numberFormatException(NumberFormatException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(400, null, "String无法转换Int"));
    }

    @ExceptionHandler(value = ConversionFailedException.class)
    public ResponseEntity conversionFailedException(ConversionFailedException e) {
        TypeDescriptor t = e.getSourceType();
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(400, null, "String无法转换Date"));
    }

    @ExceptionHandler(value = DateTimeParseException.class)
    public ResponseEntity conversionFailedException(DateTimeParseException e) {
        String t = e.getParsedString();
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(400, null, "String无法转换Date"));
    }



    @ExceptionHandler(value = TooManyResultsException.class)
    public ResponseEntity tooManyResultsException(TooManyResultsException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).
                body(new ExceptionResult(400, null, "出现重复数据"));
    }

    /**
     * 处理其他的不可知的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleException(Exception e) {
        e.printStackTrace();
        return ResponseEntity.status(500).body(new ExceptionResult(ZkExceptionEnum.SYSTEM_EXCEPTION));
    }
}
